package com.gps.client;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.gps.pojo.GPS;
import org.apache.log4j.PatternLayout;
import org.junit.Test;

import java.io.*;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.Pattern;

public class Client extends Thread {

    public static void main(String[] args) {
        Client client = new Client("127.0.0.1", 18888);
        client.start();
    }

    private static final String LONGITUDE = "[\\-+]?(0?\\d{1,2}|0?\\d{1,2}\\.\\d{1,15}|1[0-7]?\\d|1[0-7]?\\d\\.\\d{1,15}|180|180\\.0{1,15})";

    private static final String LATITUDE = "[\\-+]?([0-8]?\\d|[0-8]?\\d\\.\\d{1,15}|90|90\\.0{1,15})";

    private String ip;
    private int port;

    public Client (String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    @Override
    public void run() {
        for (;;) {
            request();
        }
    }

    public void request() {
        ObjectOutputStream oos = null;
        OutputStream os = null;
        Socket socket = null;
        try {
            System.out.println("已发起服务器连接.");
            socket = new Socket(ip, port);
            System.out.println("客户端信息：" + socket.getLocalAddress() + "  P:" + socket.getLocalPort());
            System.out.println("服务端信息：" + socket.getInetAddress() + "  P:" + socket.getPort());

            os = socket.getOutputStream();
            oos = new ObjectOutputStream(os);
//            send(oos); // 循环发送
            oos.writeObject(autoGenerateGPS());
            oos.flush();
            System.out.println("客户端结束。");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                oos.close();
                os.close();
                if(!socket.isClosed())
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void send(ObjectOutputStream oos) {
        for (;;) {
            try {
                GPS gps = autoGenerateGPS();
                if (!checkGPS(gps)) {
                    continue;
                }
                oos.writeObject(gps);
                oos.flush();
                ThreadUtil.sleep(3000);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
        }
    }

    // 模拟自动生成gps对象
    private GPS autoGenerateGPS() {
        GPS gps = new GPS(nextDouble(0.00000, 90.00000), nextBoolean(), nextDouble(0.00000, 180.00000), nextBoolean(), 1, "03", 4.4f, 32.6f, 5.4f, 3, "0000*5A");
        return gps;
    }

    /**
     * 生成max到min范围的浮点数
     * */
    private double nextDouble(final double min, final double max) {
        double result = min + ((max - min) * new Random().nextDouble());
        DecimalFormat df = new DecimalFormat("0.00000");
        return Double.parseDouble(df.format(result));
    }

    /**
     * 随机生成一个boolean值
     * @return
     */
    private boolean nextBoolean() {
        return (boolean)new Random().nextBoolean();
    }

    /**
     * 根据gps对象生成gps字符串
     * @param gps
     * @return
     */
    private String generateGPS(GPS gps) {
        return gps.toString();
    }

    public boolean checkGPS(GPS gps) {
        boolean flag = false;
        if ("$GPGGA".equals(gps.getHeader()) && checkLatitude(gps.getLatitude()+"") && checkLongitude(gps.getLongitude()+"")) {
            flag = true;
        }
        return flag;
    }

    /**
     * 检验经度合法性
     *  -180.0 ~ +180.0  小数为1到5位
     * @param longitude
     * @return
     */
    private boolean checkLongitude(String longitude) {
        if (!Pattern.matches(LONGITUDE, longitude)) {
            throw new RuntimeException("非法经度！");
        }
        return true;
    }

    /**
     * 检测纬度合法性
     * -90.0 ~ + 90.0   小数位1到5位
     * @param latitude
     * @return
     */
    // 检测纬度合法性
    private boolean checkLatitude(String latitude) {
        if (!Pattern.matches(LATITUDE, latitude)) {
            throw new RuntimeException("非法纬度!");
        }
        return true;
    }
}
